/**
 * @file poj/2828/segment_tree.cpp
 * @author Ruiming Guo (guoruiming@stu.scu.edu.cn)
 * @brief 有一个空的序列，有 n 个人要插队，第 i 个人有一个 id，
 * 这个人插入队列要排在 pos[i] 个人后面。
 * 最后从队首开始输出每个人的 id。
 *
 * 逆向思维，把插队问题改成出列问题，for i from n to 1,
 * 每个排在 pos[i] + 1 上的人出队，存下这个出队者的 id。
 * @version 1.0
 * @date 2022-05-06
 *
 * @copyright Copyright (c) 2022
 *
 **/

#include <iostream>
const int N = 200000 + 10;
int n;
int Pos[N], Val[N], Ans[N];

#define ls (rt << 1)
#define rs (rt << 1 | 1)
struct SegTree {
  int sum[4 * N];
  /**
   * @brief 使用子节点的信息更新父节点的信息
   *
   * @param rt 根节点
   **/
  void maintain(int rt) { sum[rt] = sum[ls] + sum[rs]; }
  /**
   * @brief 建立以 rt 为根节点，管理[l, r]的线段树
   *
   * @param rt 线段树的根节点
   * @param l 根节点 rt 管理的左短点
   * @param r 根节点 rt 管理的右端点
   **/
  void build(int rt, int l, int r) {
    if (l == r) {
      sum[rt] = 1;
      return;
    } else {
      int mid = l + r >> 1;
      build(ls, l, mid), build(rs, mid + 1, r);
      maintain(rt);
    }
  }
  /**
   * @brief 在以 rt 为根的树上，包括原序列上[l, r]这一段，记录 pos 位置上的人为
   *val
   *
   * @param rt 管理这一段的线段树的树根
   * @param l 这一段在原序列中的左端点
   * @param r 这一段在原序列中的右端点
   * @param pos 被改变的点的位置
   * @param val 该点被改变之后的值
   **/
  void update(int rt, int l, int r, int pos, int val) {
    if (l == r) {
      Ans[l] = val;
      sum[rt] = 0;  // 已经走到叶节点
      return;
    }
    int mid = l + r >> 1;
    if (sum[ls] >= pos)
      update(ls, l, mid, pos, val);
    else
      update(rs, mid + 1, r, pos - sum[ls], val);
    maintain(rt);  // 非叶子节点，需要调用
  }
} ST;
using namespace std;
int main() {
  ios::sync_with_stdio(0), cin.tie(0);
  while (cin >> n && n) {
    ST.build(1, 1, n);
    for (int i = 1; i <= n; ++i) {
      cin >> Pos[i] >> Val[i];
    }

    for (int i = n; i >= 1; --i) {
      ST.update(1, 1, n, Pos[i] + 1, Val[i]);
    }

    for (int i = 1; i <= n; ++i) cout << Ans[i] << ' ';
    cout << endl;
  }
}
